package com.chris.datacnter.controller;



import com.chris.datacnter.config.DataCenterConst;
import com.chris.datacnter.dao.DcRouteDAO;
import com.chris.datacnter.dao.DcRuntimeDAO;
import com.chris.datacnter.dto.ChrisException;
import com.chris.datacnter.dto.SnowFlakeSyncDataDto;
import com.chris.datacnter.model.DcRouteEo;
import com.chris.datacnter.model.DcRuntimeEo;

import com.core.data.redis.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.client.support.HttpRequestWrapper;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;

/**
 * 获取外域HTTP接口
 */
@RestController
@RequestMapping(value = {"/api/v1/snowflake"})
public class SnowFlakeController {


    @Autowired
    DcRouteDAO dcRouteDAO;

    @Autowired
    DcRuntimeDAO dcRuntimeDAO;

    @Autowired(required = false)
    RedisUtil redisUtil;

    /**
     * 通过数据进行ID同步
     *
     * @param synctag
     * @return
     */
    @RequestMapping(value = "syncdata", method = RequestMethod.GET)
    public SnowFlakeSyncDataDto syncdata(@RequestParam(value = "synctag") String synctag, @RequestParam(value = "tag", required = false) String tag, @RequestParam("ns") String ns) {
        if (synctag == null || synctag.equals(""))
            throw new ChrisException(500, "synctag不能为空");

        if (ns == null || ns.equals(""))
            throw new ChrisException(500, "命名空间不能为空");


        dcRuntimeDAO.docheck();

        SnowFlakeSyncDataDto dto = null;

        // List<DcRouteEo> list_route= dcRouteDAO.getDataByns(ns);
        //DcRouteEo dcRouteEo = null;
        // if (list_route.size()<=0)
        //     throw  new ChrisException(500,"route规则不存在");
        // else
        //     dcRouteEo=list_route.get(0);


        List<DcRuntimeEo> list_rumtime = dcRuntimeDAO.getRuntimeData(synctag, ns);

        if (list_rumtime.size() > 0) {
            //存在还未超时记录
            DcRuntimeEo dr = list_rumtime.get(0);
            //重新更新过期时间+60秒延迟
            dcRuntimeDAO.updateRuntimeData(dr.getId(), DataCenterConst.SfExpiresTime + 60000);
            dto = new SnowFlakeSyncDataDto();
            dto.setLastSyncTime(System.currentTimeMillis());
            dto.setCodeState("synchronization");
            dto.setSyncMaxTime(DataCenterConst.SfExpiresTime);
            dto.setSyncTag(dr.getSyncTag());
            dto.setDatacenterId(dr.getDatacenterId());
            dto.setWorkerId(dr.getWorkerId());
            dto.setNs(dr.getNs());
            if (tag != null && !tag.equals(""))
                dto.setTag(tag);
        } else {
            //不存在重新申请ID
            //----------获取datacenter_id , worker_id-------------------------------------
            //datacenter_id为路由固定
            // long datacenter_id = dcRouteEo.getDealDatacenterId();
            List<DcRuntimeEo> list_rumtime_all = dcRuntimeDAO.getRuntimeData(ns);
            for (long i = 0; i <= 31; i++) {
                for (long j = 0; j <= 31; j++) {
                    boolean ishave = false;
                    for (DcRuntimeEo ddr : list_rumtime_all
                    ) {
                        if (ddr.getDatacenterId() == i && ddr.getWorkerId() == j) {
                            //已经存在机器id
                            ishave = true;
                            break;
                        }
                    }
                    if (!ishave) {

                        //不存在此ID则添加
                        DcRuntimeEo n = new DcRuntimeEo();
                        if (synctag != null && !synctag.equals(""))
                            n.setSyncTag(synctag);
                        else
                            n.setSyncTag(UUID.randomUUID().toString());
                        n.setDatacenterId(i);
                        n.setWorkerId(j);
                        n.setCodeState(0);
                        n.setNs(ns);
                        //多+60实际注销时间，避免因为服务端时间和客户端不同步，服务端已经过期，客户端还在使用分发ID情况
                        n.setOffTime(LocalDateTime.now().plusSeconds(DataCenterConst.SfExpiresTime / 1000 + 60));
                        n.setLastSyncTime(LocalDateTime.now());
                        n.setSyncMaxTime(DataCenterConst.SfExpiresTime);
                        if (tag != null && !tag.equals(""))
                            n.setTag(tag);
                        dcRuntimeDAO.update(n);
                        //------------------------
                        dto = new SnowFlakeSyncDataDto();
                        dto.setLastSyncTime(System.currentTimeMillis());
                        dto.setCodeState("add");
                        dto.setSyncTag(n.getSyncTag());
                        dto.setDatacenterId(i);
                        dto.setWorkerId(j);
                        dto.setSyncMaxTime(DataCenterConst.SfExpiresTime);
                        dto.setNs(ns);
                        if (tag != null && !tag.equals(""))
                            dto.setTag(tag);
                        break;
                    }
                }
                if (dto != null)
                    break;
            }
            // for (Long i =dcRouteEo.getBegin_worker_id(); i <= dcRouteEo.getEnd_worker_id(); i++) {
            //0补位
            //  }
            //-----------------------------------------------------------------------------
        }
        return dto;
    }

    /**
     * 通过redis进行数据同步
     * 规则 d=5(0-31),w=5(0-31)，双向循环不断查找redis
     * (1)存在->更新,返回ID
     * (2)不存在->插入新建，返回ID
     *
     * @param synctag
     * @param ns
     * @param d
     * @param w
     * @return
     */
    @RequestMapping(value = "syncredis", method = RequestMethod.GET)
    public SnowFlakeSyncDataDto syncredis(@RequestParam(value = "synctag") String synctag, @RequestParam(value = "tag", required = false) String tag, @RequestParam("ns") String ns, @RequestParam("d") int d, @RequestParam("w") int w) {
        if (synctag == null || synctag.equals(""))
            throw new ChrisException(500, "synctag不能为空");

        if (redisUtil == null)
            throw new ChrisException(500, "redisUtil未初始化");





        boolean issync = false;
        //(1)查找是否存在未过期数据先判断是否存在
        SnowFlakeSyncDataDto dto = null;
        dto = redisUtil.get(String.format(DataCenterConst.Sf, ns, d, w), SnowFlakeSyncDataDto.class);
        //是否为空 && 是否是同一个 synctag  && 是否过期时间剩余时间大于 15 分钟(小于剩余时间，就当作新增，错位时间，留给判断过期）
        if (dto != null && dto.getSyncTag().equals(synctag) && (dto.getLastSyncTime()+dto.getSyncMaxTime()) > (System.currentTimeMillis()+900000) ) {
            //存在,更新过期时间，并返回
            dto.setLastSyncTime(System.currentTimeMillis());
            dto.setSyncMaxTime(DataCenterConst.SfExpiresTime);
            if (tag != null && !tag.equals(""))
                dto.setTag(tag);
            //标识同步
            dto.setCodeState("synchronization");
            issync = redisUtil.setIfPresent(String.format(DataCenterConst.Sf, ns, d, w), dto, DataCenterConst.SfExpiresTime / 1000);

        }
        if (issync) {
            return dto;
        } else {
            dto = new SnowFlakeSyncDataDto();
            dto.setNs(ns);
            //标识新增
            dto.setCodeState("add");
            dto.setSyncTag(synctag);
            dto.setSyncMaxTime(DataCenterConst.SfExpiresTime);
            if (tag != null && !tag.equals(""))
                dto.setTag(tag);
            //不存在,轮询现有 ns + d + w , 找出空
            for (long i = 0; i <= 31; i++) {
                for (long j = 0; j <= 31; j++) {
                    //dto = redisUtil.get(String.format(DataCenterConst.Sf, ns, i, j), SnowFlakeSyncDataDto.class);
                   // if (dto == null) {
                        //插入新记录。并返回
                        dto.setLastSyncTime(System.currentTimeMillis());
                        dto.setDatacenterId(i);
                        dto.setWorkerId(j);
                        //插入不存在的记录是否成功
                       if( redisUtil.setIfAbsent(String.format(DataCenterConst.Sf, ns, i, j), dto, DataCenterConst.SfExpiresTime / 1000))
                       {
                           return  dto;
                       }

                  //  }
                }

            }
        }
        return null;
    }

}
